

#ifndef _DESIGN_PATTERN_STRUCTURAL_BRIDGE_BRIDGE_H_
#define _DESIGN_PATTERN_STRUCTURAL_BRIDGE_BRIDGE_H_

#include "../../test_include.h"

namespace bridge {

class AbstractionImplement {
 public:
  virtual ~AbstractionImplement() = default;
  virtual void Operation()        = 0;
};

using AbstractionImplementSptr = std::shared_ptr<AbstractionImplement>;

//////////////////////////////////////////////////////////////////////////

class Abstraction {
 public:
  virtual ~Abstraction() = default;
  virtual void Operation() = 0;
};

class RefinedAbstraction1 : public Abstraction {
 public:
  RefinedAbstraction1(AbstractionImplementSptr impl) : impl_(std::move(impl)) {
    std::cout << "RefinedAbstraction1 ctor..." << std::endl;
  }
  ~RefinedAbstraction1() {
    std::cout << "RefinedAbstraction1 dtor..." << std::endl;
  }

  void Operation() override {
    std::cout << "RefinedAbstraction1 Operation..." << std::endl;
    this->impl_->Operation();
  }

 private:
  AbstractionImplementSptr impl_{nullptr};
};

class RefinedAbstraction2 : public Abstraction {
 public:
  RefinedAbstraction2(AbstractionImplementSptr impl) : impl_(std::move(impl)) {
    std::cout << "RefinedAbstraction2 ctor..." << std::endl;
  }
  ~RefinedAbstraction2() {
    std::cout << "RefinedAbstraction2 dtor..." << std::endl;
  }

  void Operation() override {
    std::cout << "RefinedAbstraction2 Operation..." << std::endl;
    this->impl_->Operation();
  }

 private:
  AbstractionImplementSptr impl_{nullptr};
};

//////////////////////////////////////////////////////////////////////////

class AbstractionImplement1 : public AbstractionImplement {
 public:
  AbstractionImplement1() {
    std::cout << "AbstractionImplement1 ctor..." << std::endl;
  }

  ~AbstractionImplement1() {
    std::cout << "AbstractionImplement1 dtor..." << std::endl;
  }

  void Operation() override {
    std::cout << "AbstractionImplement1 Operation..." << std::endl;
  }
};

class AbstractionImplement2 : public AbstractionImplement {
 public:
  AbstractionImplement2() {
    std::cout << "AbstractionImplement2 ctor..." << std::endl;
  }

  ~AbstractionImplement2() {
    std::cout << "AbstractionImplement2 dtor..." << std::endl;
  }

  void Operation() override {
    std::cout << "AbstractionImplement2 Operation..." << std::endl;
  }
};

//////////////////////////////////////////////////////////////////////////

void Test() {
  std::cout << std::endl;
  std::cout << "bridge/////////////////////////////////////////////////////////"
               "/////////////////"
            << std::endl;
  std::cout << std::endl;

  {
    auto abs = std::make_shared<RefinedAbstraction1>(
        std::make_shared<AbstractionImplement1>());
    abs->Operation();
  }

  {
    auto abs = std::make_shared<RefinedAbstraction1>(
        std::make_shared<AbstractionImplement2>());
    abs->Operation();
  }

  {
    auto abs = std::make_shared<RefinedAbstraction2>(
        std::make_shared<AbstractionImplement1>());
    abs->Operation();
  }

  {
    auto abs = std::make_shared<RefinedAbstraction2>(
        std::make_shared<AbstractionImplement2>());
    abs->Operation();
  }
}

}  // namespace bridge

#endif  // _DESIGN_PATTERN_STRUCTURAL_BRIDGE_BRIDGE_H_
